package tr.edu.ege.kipler.satisfiability.completion.rules.dl;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import tr.edu.ege.kipler.satisfiability.ReasonerException;
import tr.edu.ege.kipler.satisfiability.UnsatisfiableException;
import tr.edu.ege.kipler.satisfiability.container.ConceptCategory;
import tr.edu.ege.kipler.satisfiability.container.DependencyManager;
import tr.edu.ege.kipler.satisfiability.container.Individual;
import tr.edu.ege.kipler.satisfiability.container.SHOIQABox;
import tr.edu.ege.kipler.satisfiability.container.WorldConstraintSystem;
import tr.edu.ege.kipler.syntax.atomicformula.ConceptAssertion;
import tr.edu.ege.kipler.syntax.atomicformula.SameIndividualAssertion;
import tr.edu.ege.kipler.syntax.concept.Concept;
import tr.edu.ege.kipler.syntax.concept.Nominal;

/**
 * 
 * @author İnanç Seylan
 *
 */
public class SameNominalMergeRule extends ABoxRule {
	private SHOIQABox aBox;

	private boolean applied;

	private ConceptAssertion thisCa, otherCa;

	@Override
	public void apply() throws ReasonerException {
		applied = false;
		aBox = (SHOIQABox) getWorld().getABox();
		MergePair pair = null;
		for (Iterator<Concept> i = getIndividual().conceptIterator(
				ConceptCategory.NOMINAL); i.hasNext() && pair == null;) {
			Nominal nominal = (Nominal) i.next();
			for (Iterator<Individual> j = aBox.getNominals().iterator(); !nominal
					.isNegated()
					&& j.hasNext() && pair == null;) {
				Individual other = j.next();
				otherCa = new ConceptAssertion(nominal, other.getName());
				if (!getIndividual().equals(other)
						&& aBox.contains(otherCa)
						&& !aBox.contains(new SameIndividualAssertion(
								getIndividual().getName(), other.getName())
								.toggleNegated())) {
					thisCa = new ConceptAssertion(nominal, getIndividual()
							.getName());
					pair = new MergePair(other.getName(), getIndividual()
							.getName());
					getWcs().getData().getLogger().info(
							"WCS " + getWcs().getId()
									+ " Same nominal merge rule: Selected "
									+ pair.getFrom() + " to merge into "
									+ pair.getInto());
				}
			}
		}
		applyMerge(pair);
	}

	private void applyMerge(MergePair pair) throws UnsatisfiableException {
		if (pair != null) {
			new SHOIQMergeStrategy().merge(getIndividual().getName(), aBox,
					pair, prepareDependencySet());
			applied = true;
		}
	}

	private Set<WorldConstraintSystem> prepareDependencySet() {
		Set<WorldConstraintSystem> result = new HashSet<WorldConstraintSystem>();
		DependencyManager depMan = getWcs().getData().getDependencyManager();
		result.addAll(depMan.getDependencies(thisCa));
		result.addAll(depMan.getDependencies(otherCa));
		return result;
	}

	@Override
	public boolean isApplied() {
		return applied;
	}

}
